package com.djdevs.calculatorconverter;

import java.util.regex.*;

public class CalculatorParser {
	public CalculatorParser() { }
	
	public static String CalculateBraces(String txtList, int openIndex)
    {
		try {
			int closeIndex = 0;
	    	String result = "";
	    	double dblResult = 0.0;
	    	String subTxtList = txtList.substring(openIndex + 1, txtList.length());
	    	String firstTxtList = txtList.substring(0, openIndex);
	    	
			if (subTxtList.indexOf("(") != -1) {
				if (subTxtList.indexOf("(") < subTxtList.indexOf(")")) {
					result = CalculateBraces(subTxtList, subTxtList.indexOf("("));
					firstTxtList = firstTxtList + result;
				}
	    		else {
	    			closeIndex = subTxtList.indexOf(")");
	    			dblResult = evaluate(subTxtList.substring(0, closeIndex));
	    			firstTxtList = firstTxtList + dblResult;
	    			
	    			result = CalculateBraces(subTxtList.substring(closeIndex + 1, subTxtList.length())
	    					, subTxtList.substring(closeIndex + 1, subTxtList.length()).indexOf("(")); 
	    			firstTxtList = firstTxtList + result;
				}
			}
			else {
				closeIndex = subTxtList.indexOf(")");
				dblResult = evaluate(subTxtList.substring(0, closeIndex));
				firstTxtList = firstTxtList + dblResult + subTxtList.substring(closeIndex + 1, subTxtList.length());
				firstTxtList = firstTxtList.replace(")", "");
			}
			
			return firstTxtList;
		}
		catch (Exception e) {
			return "NaN";
		}
    	
    }
    
    public static boolean IfOperatorExists(String subTxtList)
    {
    	if (subTxtList.indexOf("√") != -1 || subTxtList.indexOf("±") != -1 || subTxtList.indexOf("%") != -1 || subTxtList.indexOf("/") != -1 
    			|| subTxtList.indexOf("*") != -1 || subTxtList.indexOf("+") != -1 || subTxtList.indexOf("-") != -1) {
			return true;
		}
    	return false;
    }

	public static Double evaluate(String expression) {

		double dblResult  = 0;
		String result = expression;
		CalcExpression bodmas = new CalcExpression(result);
		while(bodmas.hasMatch()) {
			double firstNumber = bodmas.getLeft();
			char operator = bodmas.getOperator();
			double secondNumber = bodmas.getRight();

			if (operator == '^') {
				dblResult = Math.pow(firstNumber, secondNumber);
				result = result.substring(0, bodmas.getStart()) + dblResult + result.substring(bodmas.getEnd());
			}
			else if (operator == '/') {
				dblResult = firstNumber / secondNumber;
				result = result.substring(0, bodmas.getStart()) + dblResult + result.substring(bodmas.getEnd());
			}
			else if (operator == '*') {
				dblResult = firstNumber * secondNumber;
				result = result.substring(0, bodmas.getStart()) + dblResult + result.substring(bodmas.getEnd());
			}
			else if (operator == '+') {
				dblResult = firstNumber + secondNumber;
				if (Math.signum(dblResult) == -1.0) {
					result = result.substring(0, bodmas.getStart()) + dblResult + result.substring(bodmas.getEnd());
				}
				else {
					if (result.substring(0, bodmas.getStart())  == "") {
						result = dblResult + result.substring(bodmas.getEnd());
					}
					else {
						result = result.substring(0, bodmas.getStart()) + "+" + dblResult + result.substring(bodmas.getEnd());
					}
				}
			}
			else if (operator == '-') {
				dblResult = firstNumber - secondNumber;
				result = result.substring(0, bodmas.getStart()) + dblResult + result.substring(bodmas.getEnd());
			}
			else if (operator == '√') {
				dblResult = Math.sqrt(secondNumber);
				result = result.substring(0, bodmas.getStart()) + dblResult + result.substring(bodmas.getEnd());
			}
			
			bodmas = new CalcExpression(result);
		}
		return Double.parseDouble(result);
	}
}

class CalcExpression {
	private double l = 0.0;
	private char o;
	private double r = 0.0;
	private int s = 0;
	private int e = 0;
	private boolean f;

	public CalcExpression(String text) {
		this.f = getMatchFor(text, '^');
		if(!this.f)
			this.f = getSqRtFor(text, '√');
		if(!this.f)
			this.f = getMatchFor(text, '/');
		if(!this.f)
			this.f = getMatchFor(text, '*');
		if(!this.f)
			this.f = getMatchFor(text, '+');
		if(!this.f)
			this.f = getMatchFor(text, '-');	
	}

	private boolean getMatchFor(String text, char operator) {
		String regex = "(-?[\\d\\.]+)(\\x)(-?[\\d\\.]+)";
		Matcher matcher = Pattern.compile(regex.replace('x', operator)).matcher(text);
		if(matcher.find()) {
			this.l = Double.parseDouble(matcher.group(1));
			this.o = matcher.group(2).charAt(0);
			this.r = Double.parseDouble(matcher.group(3));
			this.s = matcher.start();
			this.e = matcher.end();
			return true;
		}
		return false;
	}
	
	private boolean getSqRtFor(String text, char operator) {
		String regex = "(\\x)(-?[\\d\\.]+)";
		Matcher matcher = Pattern.compile(regex.replace('x', operator)).matcher(text);
		if(matcher.find()) {
			//this.l = Double.parseDouble(matcher.group(1));
			this.o = matcher.group(1).charAt(0);
			this.r = Double.parseDouble(matcher.group(2));
			this.s = matcher.start();
			this.e = matcher.end();
			return true;
		}
		return false;
	}
	
	public double getLeft() {
		return l;
	}

	public char getOperator() {
		return o;
	}

	public double getRight() {
		return r;
	}

	public int getStart() {
		return s;
	}

	public int getEnd() {
		return e;
	}

	public void setF(boolean f) {
		this.f = f;
	}

	public boolean hasMatch() {
		return f;
	}
}